//
//  Data.cpp
//  chatv
//
//  Created by 云 浮 on 12-7-9.
//  Copyright (c) 2012年 __MyCompanyName__. All rights reserved.
//

#include "Data.h"

#include "Logic.h"

using namespace FreeNet ;

// test info.
//const char localhost[] = "127.0.0.1" ;
const char localhost[] = "192.168.12.75" ;
const int login_port = 50000 ;
const int lobby_port = 50100 ;
const int session_port = 60000 ;

void* parse(void* buff) ;
void* parse(void* buff)
{
    return 0 ;
}

void* login_recv(void* param) ;
void* login_recv(void* param)
{
    while (CData::Instance()->getLoginFlag())
    {
        ::printf("login_recv function \n") ;
        sleep(1) ;
    }

    destroyThread(param) ;
    return 0 ;
}

void* lobby_recv(void* param) ;
void* lobby_recv(void* param)
{
    while (CData::Instance()->getLobbyFlag())
    {
        ::printf("lobby_recv function \n") ;
        sleep(1) ;
    }

    destroyThread(param) ;
    return 0 ;
}

int count = 0 ;
int total = 0 ;
int recvcount = 0 ;
int sendcount = 0 ;

int sessions = 0 ;
int sin = 0 ;
void* total_sessions(void* param) ;
void* total_sessions(void* param)
{
    while (1)
    {
        ::printf("total sessions [%d] [%d]\n", sessions, sessions - sin) ;
        sleep(1) ;
        sin = sessions ;
    }
    return 0 ;
}

void* session_recv(void* param) ;
void* session_recv(void* param)
{
    char recvBuf[1024] ;
    int len = 0 ;
    while (CData::Instance()->getSessionFlag())
    {
        epoll_event tmp_ev ;
        socklen_t len ;
        int fds = CData::Instance()->pEpoll->wait(-1) ;
//        if (1 < fds)
//        {
//            ::printf("fds = [%d]\n", fds) ;
//        }

        for (int i = 0; i < fds; ++i)
        {
            tmp_ev = CData::Instance()->pEpoll->remoteEvents[i] ;

            int recv_count = 0 ;

            if (tmp_ev.data.fd == CData::Instance()->getLocalInfo().fd)
            {
                int newfd = ::accept(CData::Instance()->getLocalInfo().fd, 0, &len) ;
                CData::Instance()->pEpoll->localEvent.events = EPOLLIN | EPOLLET ;
                CData::Instance()->pEpoll->localEvent.data.fd = newfd ;
                int res = fcntl(newfd, F_GETFD, 0) ;
                assert(-1 != res) ;
                assert(-1 != fcntl(newfd, F_SETFL, res | O_NONBLOCK)) ;
                CData::Instance()->pEpoll->Ctl(EPOLL_CTL_ADD, newfd) ;
//                ::printf("new accept info: [%d]\n", newfd) ;
                ++sessions ;
            }
            else if (tmp_ev.events & EPOLLIN)
            {
                char buf[1024] ;
                int res ;
                if (0 > (res = read(tmp_ev.data.fd, buf, 1024)))
                {
                    ::close(tmp_ev.data.fd) ;
                }
                else if (0 == res)
                {
                    ::close(tmp_ev.data.fd) ;
                }
                else
                {
                    // todo.
                    CData::Instance()->pEpoll->localEvent.events = EPOLLOUT | EPOLLET ;
                    CData::Instance()->pEpoll->localEvent.data.fd = tmp_ev.data.fd ;
                    CData::Instance()->pEpoll->Ctl(EPOLL_CTL_MOD, tmp_ev.data.fd) ;
                }
            }
            else if (tmp_ev.events & EPOLLOUT)
            {
                int res = write(tmp_ev.data.fd, "world\n", 5) ;
                CData::Instance()->pEpoll->localEvent.events = EPOLLIN | EPOLLET ;
                CData::Instance()->pEpoll->localEvent.data.fd = tmp_ev.data.fd ;
                CData::Instance()->pEpoll->Ctl(EPOLL_CTL_MOD, tmp_ev.data.fd) ;
            }
            else if (tmp_ev.events & EPOLLERR)
            {
                ::printf("EPOLLERR\n") ;
            }
            else
            {
                ::printf("else case ======== \n") ;
            }
        }
    }

    destroyThread(param) ;
    return 0 ;
}

CData* CData::pData = 0 ;
CData* CData::Instance()
{
    if (0 == pData)
    {
        pData = new CData() ;
    }
    return pData ;
}

void CData::initData()
{
//    strcpy(loginInfo.ip, localhost) ;
//    loginInfo.port = login_port ;
//    loginInfo.mode = NET_TCP ;
//    loginInfo.fd = connectServer(loginInfo.ip, loginInfo.port, loginInfo.mode, 0) ;
//    assert(-1 != loginInfo.fd) ;
//    
//    lobbyMax = 1 ;
//    lobbyInfos = new sNetInfo[lobbyMax] ;
//    for (int i = 0; i < lobbyMax; ++i)
//    {
//        strcpy(lobbyInfos[i].ip, localhost) ;
//        lobbyInfos[i].port = lobby_port + i ;
//        lobbyInfos[i].mode = NET_TCP ;
//        lobbyInfos[i].fd = connectServer(lobbyInfos[i].ip, lobbyInfos[i].port, lobbyInfos[i].mode, 0) ;
//        assert(-1 != lobbyInfos[i].fd) ;
//    }

    sessionMax = 1000 ;
    sessionCount = 0 ;
    sessionInfos = new sSessionInfo[sessionMax] ;
    for (int i = 0; i < sessionMax; ++i)
    {
        sessionInfos[i].fd = -1 ;
    }

    pEpoll = new CEpoll(1000, localhost, session_port) ;
    ::memcpy(&localInfo, &(pEpoll->localInfo), sizeof(sNetInfo)) ;

    pthread_t tt ;
    createThread(tt, total_sessions, 0) ;

    // create session thread.
    sessionFlag = true ;
    sessionMsgID = createQueue(8 * 1024) ; // 8 MB.
    createThread(sessionThread, session_recv, 0) ;
    createThread(sessionThread, session_recv, 0) ;
    createThread(sessionThread, session_recv, 0) ;
    createThread(sessionThread, session_recv, 0) ;
    createThread(sessionThread, session_recv, 0) ;
}

CData::CData()
{
}

CData::~CData()
{
    loginFlag = lobbyFlag = sessionFlag = false ;

    delete [] lobbyInfos ;
    delete [] sessionInfos ;

    delete CData::pData ;

    delete pEpoll ;
}

int CData::addSession(const int fd, const int uuid, const int lobbyID, const char* ip, const int port)
{
    assert(-1 < fd) ;
    for (int i = 0; i < sessionMax; ++i)
    {
        if (-1 == sessionInfos[i].fd)
        {
            sessionInfos[i].fd = fd ;
            sessionInfos[i].uuid = uuid ;
            sessionInfos[i].index = i ;
            sessionInfos[i].lobbyID = lobbyID ;
            strcpy(sessionInfos[i].ip, ip) ;
            sessionInfos[i].port = port ;
            ++sessionCount ;
            return sessionInfos[i].index ;
        }
    }
    return -1 ;
}

int CData::addSession(const sSessionInfo info)
{
    assert(-1 < info.fd) ;
    for (int i = 0; i < sessionMax; ++i)
    {
        if (-1 == sessionInfos[i].fd)
        {
            ::memcpy(&(sessionInfos[i]), &info, sizeof(sSessionInfo)) ;
            sessionInfos[i].index = i ;
            ++sessionCount ;
            return sessionInfos[i].index ;
        }
    }
    return -1 ;
}

int CData::clearSessions()
{
    int res = 0 ;
    for (int i = 0; i < sessionMax; ++i)
    {
        if (-1 == sessionInfos[i].fd)
        {
            continue ;
        }
        disconnectSession(sessionInfos[i].fd, 0) ;
        sessionInfos[i].fd = -1 ;
        --sessionCount ;
        ++res ;
    }
    assert(0 == sessionCount) ;
    return res ;
}

int CData::delSessionByFD(const int fd)
{
    assert(-1 < fd) ;
    int res = -1 ;
    for (int i = 0; i < sessionMax; ++i)
    {
        if (fd == sessionInfos[i].fd)
        {
            disconnectSession(sessionInfos[i].fd, 0) ;
            sessionInfos[i].fd = -1 ;
            res = sessionInfos[i].index ;
            --sessionCount ;
            break ;
        }
    }
    return res ;
}

int CData::delSessionByUUID(const int uuid)
{
    assert(-1 < uuid) ;
    int res = -1 ;
    for (int i = 0; i < sessionMax; ++i)
    {
        if (-1 == sessionInfos[i].fd)
        {
            continue ;
        }
        if (uuid != sessionInfos[i].uuid)
        {
            continue ;
        }

        disconnectSession(sessionInfos[i].fd, 0) ;
        sessionInfos[i].fd = -1 ;
        res = sessionInfos[i].index ;
        --sessionCount ;
        break ;
    }
    return res ;
}

int CData::delSessionByIndex(const int index)
{
    assert(-1 < index && index < sessionMax) ;
    if (-1 == sessionInfos[index].fd)
    {
        return -1 ;
    }

    disconnectSession(sessionInfos[index].fd, 0) ;
    sessionInfos[index].fd = -1 ;
    --sessionCount ;

    assert(sessionInfos[index].index == index) ;
    return index ;
}

int CData::delSessionByLobbyID(const int lobbyID)
{
    assert(-1 < lobbyID && lobbyID < lobbyMax) ;
    int res = 0 ;
    for (int i = 0; i < sessionMax; ++i)
    {
        if (-1 == sessionInfos[i].fd)
        {
            continue ;
        }
        if (lobbyID == sessionInfos[i].lobbyID)
        {
            disconnectSession(sessionInfos[i].fd, 0) ;
            sessionInfos[i].fd = -1 ;
            --sessionCount ;
            ++res ;
        }
    }
    return res ;
}

int CData::delSessionByIP(const char* ip)
{
    assert(0 != ip && 0 != strcmp("", ip)) ;
    int res = 0 ;
    for (int i = 0; i < sessionMax; ++i)
    {
        if (-1 == sessionInfos[i].fd)
        {
            continue ;
        }
        if (0 != strcmp(sessionInfos[i].ip, ip))
        {
            continue ;
        }

        disconnectSession(sessionInfos[i].fd, 0) ;
        sessionInfos[i].fd = -1 ;
        --sessionCount ;
        ++res ;
    }
    return res ;
}

int CData::delSessionByPort(const int port)
{
    assert(-1 < port) ;
    int res = 0 ;
    for (int i = 0; i < sessionMax; ++i)
    {
        if (-1 == sessionInfos[i].fd)
        {
            continue ;
        }
        if (port != sessionInfos[i].port)
        {
            continue ;
        }
        disconnectSession(sessionInfos[i].fd, 0) ;
        sessionInfos[i].fd = -1 ;
        --sessionCount ;
        ++res ;
    }
    return -1 ;
}

const sSessionInfo* CData::getSessionInfoByFD(const int fd) const
{
    assert(-1 < fd) ;
    for (int i = 0; i < sessionMax; ++i)
    {
        if (fd == sessionInfos[i].fd)
        {
            return &(sessionInfos[i]) ;
        }
    }
    return 0 ;
}

const sSessionInfo* CData::getSessionInfoByUUID(const int uuid) const
{
    assert(-1 < uuid) ;
    for (int i = 0; i < sessionMax; ++i)
    {
        if (-1 == sessionInfos[i].fd)
        {
            continue ;
        }
        if (uuid == sessionInfos[i].uuid)
        {
            return &(sessionInfos[i]) ;
        }
    }
    return 0 ;
}

const sSessionInfo* CData::getSessionInfoByIndex(const int index) const
{
    assert(-1 < index && index < sessionMax) ;
    if (-1 == sessionInfos[index].fd)
    {
        return 0 ;
    }
    assert(index == sessionInfos[index].index) ;
    return &(sessionInfos[index]) ;
}

int CData::sendToLogin(const void* data, const int len)
{
    assert(0 != data && 0 < len) ;
    return (0 < sendMessage(data, len, loginInfo.fd, 0)) ;
}

int CData::sendToLobby(const void* data, const int len, const int lobbyID)
{
    assert(0 != data && 0 < len) ;
    assert(-1 < lobbyID && lobbyID < lobbyMax) ;
    return (0 < sendMessage(data, len, lobbyInfos[lobbyID].fd, 0)) ;
}

int CData::sendToClient(const void* data, const int len, const int fd)
{
    assert(0 != data && 0 < len) ;
    assert(-1 < fd) ;
    const sSessionInfo* pClient = CData::Instance()->getSessionInfoByFD(fd) ;
    return (0 < sendMessageTo(pClient->ip, pClient->port, data, len, 0)) ;
}
























